#pragma once

#include <iostream>
#include <queue>
#include <unistd.h>
#include <pthread.h>

namespace BlockQueueModule
{
    static int gcap = 10;
    template <class T>
    class BlockQueue
    {
    private:
        bool IsFull()
        {
            return _q.size() == _cap;
        }
        bool IsEmpty()
        {
            return _q.empty();
        }
    public:
        BlockQueue(int cap = gcap)
            : _cap(cap)
            ,_cwait_num(0)
            ,_pwait_num(0)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_productor_cond, nullptr);
            pthread_cond_init(&_consumer_cond, nullptr);
        }
        void Equeue(const T &in) // 生产者
        {
            pthread_mutex_lock(&_mutex);
            while(IsFull())  //条件判断将if->while,为了规避伪唤醒！
            {
                printf("生产者进入等待...\n");
                _pwait_num++;
                //等待时，释放_mutex
                pthread_cond_wait(&_productor_cond,&_mutex);  //必然在临界区中等待,必然会持有锁
                //线程被唤醒&&重新申请持有锁，会在临界区内醒来
                _pwait_num--;
                printf("生产者被唤醒...\n");
            }
            //if(IsFull())不满足 || 线程被唤醒
            _q.push(in);
            //肯定有资源
            if(_cwait_num)
            {
                pthread_cond_signal(&_consumer_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        void Pop(T* out) //消费者
        {
            pthread_mutex_lock(&_mutex);
            while(IsEmpty())    //条件判断将if->while,为了规避伪唤醒！
            {
                printf("消费者进入等待...\n");
                _cwait_num++;
                pthread_cond_wait(&_consumer_cond,&_mutex);
                _cwait_num--;
                printf("消费者被唤醒...\n");
            }
            //if(IsEmpty())不满足 || 线程被唤醒
            *out = _q.front();
            _q.pop();
            //资源一定不为满
            if(_pwait_num)
            {
                pthread_cond_signal(&_productor_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_productor_cond);
            pthread_cond_destroy(&_consumer_cond);
        }

    private:
        std::queue<T> _q;               // 保存数据的容器,临界资源
        int _cap;                       // bq的最大容量
        pthread_mutex_t _mutex;         // 互斥
        pthread_cond_t _productor_cond; // 生产者条件变量
        pthread_cond_t _consumer_cond;  // 消费者条件变量

        int _cwait_num;
        int _pwait_num;
    };
}